#include "Asteroids.h"
#include "game\World.h"
#include "utils\Log.h"
#include "..\..\Constants.h"
#include "..\..\GameEventData.h"
#include "..\..\AstroMath.h"

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
Asteroids::Asteroids(ds::DynamicSpriteNode* spriteNode) : m_Sprites(spriteNode) , m_CD(gEngine->getCollisionDetector()) {
	rand.seed(GetTickCount());
}

// ----------------------------------------------------------
// It will check if it is time to spawn a new asteroid
// ----------------------------------------------------------
void Asteroids::spawnAsteroids(float elapsed) {
	m_SpawnTimer += elapsed;
	if ( m_SpawnTimer > 4.0f ) {
		m_SpawnTimer = 0.0f;
		if ( m_AsteroidCounter < m_MaxAsteroids ) {
			createAsteroid(3);		
			++m_AsteroidCounter;
		}
	}
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void Asteroids::createAsteroid(int type) {	
	int max = SCR_MAX_X - ASTEROID_SIZES[type] - 10;
	float xp = 50.0f + rand()*(float)max;
	float angle = 45.0f + rand()*45.0f;
	addAsteroid(type,ds::Vec2(xp,10.0f),angle);
}

// ----------------------------------------------------------
// Starts a new wave 
// ----------------------------------------------------------
void Asteroids::startWave(uint32 max) {
	m_SpawnTimer = 100.0f;
	m_TotalKills = max;
	m_CurrentKills = 0;
	m_AsteroidCounter = 0;
	m_MaxAsteroids = max;
}

// ----------------------------------------------------------
// This will create a new asteroid near the given position
// ----------------------------------------------------------
void Asteroids::addAsteroid(int type,const ds::Vec2& pos,float angle) {
	Asteroid a;
	a.size = ASTEROID_SIZES[type];
	int r = a.size / 2;
	a.pos = pos;
	a.energy = 20 + type * 20;
	a.type = type;
	a.timer = 0.0f;
	float v = 300.0f - type * 30.0f;
	a.velocity = ds::MathHelper::getRadialVelocity(angle,v);
	a.handle = m_CD.addCircle(ds::Vec2(0,0),ds::Vec2(r,r),r,ASTEROID_ID);
	a.energy = 20 + type * 20;
	a.sprite = new ds::Sprite(pos,ASTEROID_TEXTURES_RECTS[type]);
	m_Asteroids.push_back(a);		
}

// ----------------------------------------------------------
// 
// ----------------------------------------------------------
Asteroid& Asteroids::getAsteroid(uint32 index) {
	AsteroidList::iterator ait = m_Asteroids.begin();
	while ( ait != m_Asteroids.end() ) {		
		if ( ait->handle == index ) {
			return *ait;
		}
		++ait;
	}	
}

// ----------------------------------------------------------
// This method will remove an asteroid for the given physics
// handle. If it is not the small one it will spawn two new
// asteroids
// ----------------------------------------------------------
void Asteroids::killAsteroid(uint32 index) {
	AsteroidList::iterator ait = m_Asteroids.begin();
	int t = -1;
	ds::Vec2 splitPos;
	while ( ait != m_Asteroids.end() ) {		
		if ( ait->handle == index ) {
			ait->energy -= 10;
			if ( ait->energy <= 0 ) {
				AsteroidEvent ae;
				ae.position = ait->pos;
				ae.type = ait->type;
				ae.size = ait->size;
				splitPos = ait->pos;							
				FIRE_EVENT(EVN_ASTEROID_DESTROYED,&ae,sizeof(AsteroidEvent));
				t = ait->type;				
				m_CD.remove(ait->handle);
				delete ait->sprite;
				ait = m_Asteroids.erase(ait);
				++m_CurrentKills;							
			}
			else {
				++ait;
			}
		}
		else {
			++ait;
		}
	}
	if ( t > 0 ) {		
		m_TotalKills += 2;
		addAsteroid(t-1,splitPos,225.0f);
		addAsteroid(t-1,splitPos,315.0f);
	}
	if ( m_CurrentKills == m_TotalKills ) {
		FIRE_EMPTY_EVENT(EVN_LEVEL_FINISHED);
	}
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void Asteroids::update(float elapsed) {
	spawnAsteroids(elapsed);	
	// update asteroids
	for ( size_t i = 0; i < m_Asteroids.size(); ++i ) {
		Asteroid* a = &m_Asteroids[i];
		a->pos += a->velocity * elapsed;
		float bottom = SCR_MAX_Y - a->size;
		float right = SCR_MAX_X - a->size;
		if ( outside(a->pos.y,0.0f,bottom) ) {
			a->velocity.y *= -1.0f;
			a->pos += a->velocity * elapsed;
		}
		if ( outside(a->pos.x,0.0f,right) ) {
			a->velocity.x *= -1.0f;
			a->pos += a->velocity * elapsed;
		}
		a->timer += elapsed;
		a->sprite->rotation = a->timer;
		a->sprite->position = a->pos;
		m_CD.setPosition(a->handle,a->pos);
		m_Sprites->addSprite(a->sprite);
	}
}
